package com.example.yijian.edit.timelineEditor;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.security.identity.InvalidReaderSignatureException;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.annotation.RequiresApi;

import com.bumptech.glide.Glide;
import com.example.yijian.R;
import com.example.yijian.edit.data.BackupData;
import com.example.yijian.edit.data.ChangeSpeedCurveInfo;
import com.example.yijian.utils.Constants;
import com.example.yijian.utils.LogUtils;
import com.example.yijian.utils.ScreenUtils;
import com.example.yijian.utils.ToastUtil;
import com.example.yijian.utils.datainfo.ClipInfo;
import com.meicam.sdk.NvsMultiThumbnailSequenceView;

import java.util.ArrayList;
import java.util.Calendar;

/**
 * Created by admin on 2018/6/8.
 * NvsTimelineEditor控件，封装NvsMultiThumbnailSequenceView与NvsTimelineTimeSpan。NvsMultiThumbnailSequenceView显示视频序列图片，
 * 可以在NvsMultiThumbnailSequenceView上添加多个NvsTimelineTimeSpan，从而方便编辑贴纸跟字幕。
 * <p>
 * The NvsTimelineEditor control encapsulates NvsMultiThumbnailSequenceView and NvsTimelineTimeSpan. NvsMultiThumbnailSequenceView displays video sequence pictures,
 *   Multiple NVsTimelineTimeSpan can be added to NVsMultiThumbnailSequenceView to facilitate editing of stickers and subtitles
 */
public class NvsTimelineEditor extends RelativeLayout {
    private String TAG = "NvsTimelineEditor";
    private static final float TIMEBASE = 1000000f;
    /*
     * 每微秒显示的像素值
     * Pixel value displayed every microsecond
     * */
    private double m_pixelPerMicrosecond = 0D;
    /*
     * 每微秒显示的最大像素值
     * Maximum pixel value displayed per microsecond
     * */
    private double m_maxPixelPerMicrosecond = 0D;
    /*
     * 每微秒显示的最小像素值
     * Minimum pixel value displayed every microsecond
     * */
    private double m_minPixelPerMicrosecond = 0D;
    private Context m_context;
    /*
     * 1、顶部时间线
     * 2、开启关闭原声按钮
     * 3、添加音频
     * */
    private LinearLayout m_rootLinearLayout;
    private RelativeLayout m_timeSpanRelativeLayout;
    private LinearLayout m_sequenceLinearLayout;


    private OnScrollChangeListener m_scrollchangeListener;
    private OnSpanExtSelectListener m_spanExtSelectListener;
    private OnMuteSelectListener m_muteSelectListener;
    /*
     * 添加的TimeSpan集合
     * Added TimeSpan collection
     * */
    private ArrayList<NvsTimelineTimeSpan> m_timelineTimeSpanArray;
    private ArrayList<NvsTimelineTimeSpanExt> m_timelineTimeSpanExtArray;
    private ArrayList<TimeSpanSplitView> m_timeSpanSplitArray;
    /*
     * 时间线timeline上的时长
     * Duration on timeline
     * */
    private long m_timelineDuration = 0;
    private MultiThumbnailSequenceView m_multiThumbnailSequenceView;
    private int m_screenCentral = 0;

    private int sequenceTopPadding = 0;
    /*
     * m_multiThumbnailSequenceView左边填充值
     * m_multiThumbnailSequenceView left padding value
     * */
    public int m_timeTextWidth = 0;
    /*
     * m_multiThumbnailSequenceView左边填充值
     * m_multiThumbnailSequenceView left padding value
     * */
    private int m_sequencLeftPadding = 0;
    /*
     * m_multiThumbnailSequenceView右边填充值
     * m_multiThumbnailSequenceView right padding value
     * */
    private int m_sequencRightPadding = 0;
    /*
     * TimeSpan左边填充值
     * TimeSpan left padding value
     * */
    private int m_timeSpanLeftPadding = 0;

    /*
     * 目前有两种timeSpan:NvsTimelineTimeSpan,NvsTimelineTimeSpanExt
     * There are currently two types of timeSpan: NvsTimelineTimeSpan, NvsTimelineTimeSpanExt
     * */
    private String m_timeSpanType = "NvsTimelineTimeSpan";//

    private boolean isMute;
    private LinearLayout voiceControl;
    private ImageView ivVoiceMute;
    private TextView tvVoiceMute;
    private TextView addVoice;

    public boolean isMute() {
        return isMute;
    }

    public void setMute(boolean mute) {
        isMute = mute;
        Glide.with(m_context).load(mute ? R.mipmap.icon_voice_open : R.mipmap.icon_voice_close).into(ivVoiceMute);
        tvVoiceMute.setText(mute ? "开启原声" : "关闭原声");
    }

    /*
     * 滑动需要的回调API
     * Callback API required for sliding
     * */
    public interface OnScrollChangeListener {
        void onScrollX(long timeStamp);
    }

    public void setOnScrollListener(OnScrollChangeListener listener) {
        m_scrollchangeListener = listener;
    }


    /*
     * 开启关闭原声
     * */
    public interface OnMuteSelectListener {
        void onMuteClick();
    }

    public void setMuteSelectListener(OnMuteSelectListener m_muteSelectListener) {
        this.m_muteSelectListener = m_muteSelectListener;
    }

    /*
     * 选中视频片段
     * */
    public interface OnSpanExtSelectListener {
        void onSpanSelect(NvsTimelineTimeSpanExt spanExt);

        void onSpanMove(long timeStamp);
    }

    public void setSpanExtSelectListener(OnSpanExtSelectListener m_spanExtSelectListener) {
        this.m_spanExtSelectListener = m_spanExtSelectListener;
    }

    public NvsTimelineEditor(Context context, AttributeSet attrs) {
        super(context, attrs);
        m_context = context;
        m_timeSpanRelativeLayout = new RelativeLayout(context);
        m_rootLinearLayout = new LinearLayout(context);
        m_rootLinearLayout.setOrientation(LinearLayout.VERTICAL);
        m_sequenceLinearLayout = new LinearLayout(context);
        m_sequenceLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
        m_multiThumbnailSequenceView = new MultiThumbnailSequenceView(context);
        init();
    }

    public void setPixelPerMicrosecond(double pixelPerMicrosecond) {
        this.m_pixelPerMicrosecond = pixelPerMicrosecond;
    }

    public void setSequencLeftPadding(int sequencLeftPadding) {
        this.m_sequencLeftPadding = sequencLeftPadding;
    }

    public void setSequencRightPadding(int sequencRightPadding) {
        this.m_sequencRightPadding = sequencRightPadding;
    }

    public void setTimeSpanLeftPadding(int timeSpanLeftPadding) {
        this.m_timeSpanLeftPadding = timeSpanLeftPadding;
    }

    /*
     * 添加timeSpan之前必须设置这个参数
     * This parameter must be set before adding timeSpan
     * */
    public void setTimeSpanType(String timeSpanType) {
        this.m_timeSpanType = timeSpanType;
    }

    /*
     * 初始化TimelineEditor
     * Initialize TimelineEditor
     * */
    public void initTimelineEditor(ArrayList<MultiThumbnailSequenceView.ThumbnailSequenceDesc> sequenceDesc, final long timelineDuration) {
        postInvalidate();
        int len = sequenceDesc.size();
        if (0 == len)
            return;
        m_timelineDuration = timelineDuration;
        /*
         * 删除所有布局
         * Delete all layouts
         * */
        removeAllLayout();
        m_sequenceLinearLayout.scrollTo(0, 0);
        m_rootLinearLayout.scrollTo(0, 0);
        m_multiThumbnailSequenceView.setThumbnailSequenceDescArray(sequenceDesc);
        m_multiThumbnailSequenceView.setPixelPerMicrosecond(m_pixelPerMicrosecond);
        m_multiThumbnailSequenceView.setStartPadding(m_sequencLeftPadding);
        m_multiThumbnailSequenceView.setEndPadding(m_sequencRightPadding);
        LayoutParams sequenceViewParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        sequenceViewParams.setMargins(0, sequenceTopPadding, 0, 0);
        this.addView(m_multiThumbnailSequenceView, sequenceViewParams);
        addTimeLineSpan(timelineDuration);
        addVoiceControlView();
        addVoiceView(timelineDuration);
        LayoutParams itemParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        this.addView(m_rootLinearLayout, itemParams);

        m_multiThumbnailSequenceView.setOnScrollChangeListenser((nvsMultiThumbnailSequenceView, i, i1) -> {
//            if (m_timeSpanType.compareTo("NvsTimelineTimeSpanExt") == 0) {
//                return;
//            }
            long tmpTimeStamp = (long) Math.floor(i / m_pixelPerMicrosecond + 0.5D);
            if (m_scrollchangeListener != null) {
                m_scrollchangeListener.onScrollX(tmpTimeStamp);
            }
            m_sequenceLinearLayout.scrollTo(i, 0);
            m_rootLinearLayout.scrollTo(i, 0);
            int timeSpanCount = m_timelineTimeSpanArray.size();
            for (int index = 0; index < timeSpanCount; ++index) {
                boolean add = true;
                NvsTimelineTimeSpan timeSpan = m_timelineTimeSpanArray.get(index);
                long inPoint = timeSpan.getInPoint();
                long outPoint = timeSpan.getOutPoint();
                if (outPoint <= m_multiThumbnailSequenceView.mapTimelinePosFromX(0))
                    add = false;
                if (inPoint >= m_multiThumbnailSequenceView.mapTimelinePosFromX(2 * m_screenCentral))
                    add = false;
                if (add) {
                    if (timeSpan.getParent() == null) {
                        m_timeSpanRelativeLayout.addView(timeSpan);
                    }
                    updateTimeSpanShadow(timeSpan);
                } else {
                    if (timeSpan.getParent() != null) {
                        m_timeSpanRelativeLayout.removeView(timeSpan);
                    }
                }
            }
        });
        MultiThumbnailSequenceView.ContentView contentView = m_multiThumbnailSequenceView.getContentView();
        if (contentView != null) {
            contentView.setOnTouchListener(new OnTouchListener() {
                @SuppressLint("ClickableViewAccessibility")
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    getCurrentSpan(event.getX());
                    return false;
                }
            });
        }
    }

    /**
     * 添加片段选中Span及判断中间分割线
     *
     * @param mClipInfoArray
     * @param clipInfoArray
     */
    public void addTimeSpanExt(ArrayList<MultiThumbnailSequenceView.ThumbnailSequenceDesc> mClipInfoArray, ArrayList<ClipInfo> clipInfoArray) {
        m_timelineTimeSpanExtArray.clear();
        m_timeSpanSplitArray.clear();
        m_timeSpanRelativeLayout.removeAllViews();
        setTimeSpanType("NvsTimelineTimeSpanExt");
        for (int i = 0; i < mClipInfoArray.size(); i++) {
            m_timelineTimeSpanExtArray.add(addTimeSpanExt(mClipInfoArray.get(i).inPoint, mClipInfoArray.get(i).outPoint, clipInfoArray.get(i).getCurveSpeed(), i));
        }
    }

    /**
     * 显示指定视频片段Span
     *
     * @param
     */
    public void selectTimeSpanSplit(int index) {
        if (m_timeSpanSplitArray.size() == 0) {
            return;
        }
        if (index > m_timeSpanSplitArray.size()) {
            return;
        }
        m_timeSpanSplitArray.get(index).setVisibility(VISIBLE);
    }

    /**
     * 视频片段中间分割线显示状态
     *
     * @param show
     */
    private void unSelectTimeSpanSplit(boolean show) {
        if (m_timeSpanSplitArray.size() == 0) {
            return;
        }
        for (int i = 0; i < m_timeSpanSplitArray.size(); i++) {
            m_timeSpanSplitArray.get(i).setVisibility(show ? VISIBLE : INVISIBLE);
        }
    }

    /**
     * 选中当前视频片段
     *
     * @param x 根据坐标
     */
    private void getCurrentSpan(float x) {
        if (m_timelineTimeSpanExtArray.size() == 0) {
            return;
        }
        long curDuration = (long) ((x - m_sequencLeftPadding - m_timeTextWidth) / m_pixelPerMicrosecond);
        for (int i = 0; i < m_timelineTimeSpanExtArray.size(); i++) {
            if (m_timelineTimeSpanExtArray.get(i).getInPoint() < curDuration && m_timelineTimeSpanExtArray.get(i).getOutPoint() > curDuration) {
                if (m_spanExtSelectListener != null && m_timelineTimeSpanExtArray.get(i).getVisibility() == View.INVISIBLE) {
                    m_spanExtSelectListener.onSpanSelect(m_timelineTimeSpanExtArray.get(i));
                }
                m_timelineTimeSpanExtArray.get(i).setVisibility(m_timelineTimeSpanExtArray.get(i).getVisibility() == View.VISIBLE ? INVISIBLE : VISIBLE);
                unSelectTimeSpanSplit(m_timelineTimeSpanExtArray.get(i).getVisibility() == View.INVISIBLE);
            } else {
                m_timelineTimeSpanExtArray.get(i).setVisibility(INVISIBLE);
            }
        }
    }


    /**
     * 选中当前视频片段
     *
     * @param curDuration 根据当前视频时间
     */
    public void getCurrentSpan(long curDuration) {
        if (m_timelineTimeSpanExtArray.size() == 0) {
            return;
        }
        for (int i = 0; i < m_timelineTimeSpanExtArray.size(); i++) {
            if (m_timelineTimeSpanExtArray.get(i).getInPoint() < curDuration && m_timelineTimeSpanExtArray.get(i).getOutPoint() > curDuration) {
                if (m_spanExtSelectListener != null && m_timelineTimeSpanExtArray.get(i).getVisibility() == View.INVISIBLE) {
                    m_spanExtSelectListener.onSpanSelect(m_timelineTimeSpanExtArray.get(i));
                }
                m_timelineTimeSpanExtArray.get(i).setVisibility(m_timelineTimeSpanExtArray.get(i).getVisibility() == View.VISIBLE ? INVISIBLE : VISIBLE);
                unSelectTimeSpanSplit(m_timelineTimeSpanExtArray.get(i).getVisibility() == View.INVISIBLE);
            } else {
                m_timelineTimeSpanExtArray.get(i).setVisibility(INVISIBLE);
            }
        }
    }

    // 关闭原声、开启原声
    private void addVoiceControlView() {
        voiceControl = (LinearLayout) LayoutInflater.from(m_context).inflate(R.layout.view_control_voice, null, false);
        ivVoiceMute = voiceControl.findViewById(R.id.iv_voice_control);
        tvVoiceMute = voiceControl.findViewById(R.id.tv_voice_control);
        LayoutParams voiceLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, ScreenUtils.dip2px(m_context, 40));
        voiceLayoutParams.setMargins(m_sequencLeftPadding - ScreenUtils.dip2px(m_context, 30), ScreenUtils.dip2px(m_context, 30), 0, 0);
        voiceControl.setLayoutParams(voiceLayoutParams);
        ViewGroup parent = (ViewGroup) voiceControl.getParent();
        if (parent != null) {
            parent.removeView(voiceControl);
        }
        voiceControl.setOnClickListener(v -> {
            if (m_muteSelectListener != null) {
                m_muteSelectListener.onMuteClick();
            }
        });
        m_rootLinearLayout.addView(voiceControl);

    }

    // + 添加音频
    private void addVoiceView(long timelineDuration) {
        double width = timelineDuration * m_pixelPerMicrosecond;
        int spanWidth = (int) Math.floor(width + 0.5D);
        addVoice = new TextView(m_context);
        addVoice.setText("+ 添加音频");
        addVoice.setTextColor(Color.WHITE);
        addVoice.setTextSize(12);
        addVoice.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
        addVoice.setBackgroundColor(Color.parseColor("#151515"));
        addVoice.setPadding(ScreenUtils.dip2px(m_context, 15), 0, 0, 0);
        LayoutParams layoutParams = new LayoutParams(spanWidth, ScreenUtils.dip2px(m_context, 40));
        layoutParams.setMargins(m_sequencLeftPadding + m_timeTextWidth, ScreenUtils.dip2px(m_context, 10), 0, 0);
        addVoice.setLayoutParams(layoutParams);
        m_rootLinearLayout.addView(addVoice);
    }

    //添加timeSpan
    public NvsTimelineTimeSpan addTimeSpan(long inPoint, long outPoint) {
        NvsTimelineTimeSpan timelineTimeSpan = createTimeSpan(inPoint, outPoint);
        if (timelineTimeSpan != null) {
            long minDuaration = 2 * Constants.NS_TIME_BASE;
            long maxDuaration = m_timelineDuration;
            int minTimeSpanPixel = (int) Math.floor(minDuaration * m_pixelPerMicrosecond + 0.5D);
            int maxTimeSpanPixel = (int) Math.floor(maxDuaration * m_pixelPerMicrosecond + 0.5D);
            timelineTimeSpan.setMinTimeSpanPixel(minTimeSpanPixel);
            timelineTimeSpan.setMaxTimeSpanPixel(maxTimeSpanPixel);
        }
        return timelineTimeSpan;
    }

    //顶部时间线
    public void addTimeLineSpan(long duration) {
        LinearLayout rootView = new LinearLayout(m_context);
        rootView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        rootView.setOrientation(LinearLayout.HORIZONTAL);

        int times = (int) Math.floor(duration / 1000000);

        int totalWidth = getSequenceWidth();
        double width = duration * m_pixelPerMicrosecond;
        int spanWidth = (int) Math.floor(width + 0.5D);
        this.m_timeTextWidth = spanWidth / times / 2;
        m_multiThumbnailSequenceView.setStartPadding(m_sequencLeftPadding + m_timeTextWidth);
        m_multiThumbnailSequenceView.setEndPadding(m_sequencRightPadding - m_timeTextWidth);
        int leftMargin = (int) Math.floor(0.5D);
        LayoutParams spanItemParams = new LayoutParams(spanWidth, ScreenUtils.dip2px(m_context, 20));
        spanItemParams.setMargins(m_sequencLeftPadding, LayoutParams.MATCH_PARENT, totalWidth - (leftMargin + spanWidth), 0);
        rootView.setLayoutParams(spanItemParams);
        rootView.setGravity(Gravity.CENTER_VERTICAL);
        for (int i = 0; i < times; i++) {
            TextView textView = new TextView(m_context);
            textView.setText(i % 2 == 0 ? formatTimeStrWithUs(i * 1000000) : "·");
            textView.setTextColor(Color.LTGRAY);
            textView.setTextSize(10);
            textView.setGravity(Gravity.CENTER);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(spanWidth / times, LayoutParams.WRAP_CONTENT);
            textView.setLayoutParams(layoutParams);
            rootView.addView(textView);
        }
        m_rootLinearLayout.addView(rootView, 0);
//        m_timeSpanRelativeLayout.addView(rootView);
    }

    //formate time
    private String formatTimeStrWithUs(long us) {
        int second = (int) (us / 1000000.0);
        int hh = second / 3600;
        int mm = second % 3600 / 60;
        int ss = second % 60;
        return hh > 0 ? String.format("%02d:%02d:%02d", hh, mm, ss) : String.format("%02d:%02d", mm, ss);
    }

    /*
     * 添加douyin timeSpan
     * Add douyin timeSpan
     * */
    public NvsTimelineTimeSpan addDouyinTimeSpan(long inPoint, long outPoint) {
        NvsTimelineTimeSpan timelineTimeSpan = createTimeSpan(inPoint, outPoint);
        if (timelineTimeSpan != null) {
            //
            timelineTimeSpan.getLeftHandleView().setBackgroundResource(R.mipmap.trimline_select_left);
            timelineTimeSpan.getRightHandleView().setBackgroundResource(R.mipmap.trimline_select_right);
            timelineTimeSpan.getTimeSpanshadowView().setBackgroundColor(Color.TRANSPARENT);
            //
            long minDuaration = 3 * Constants.NS_TIME_BASE;
            long maxDuaration = 15 * Constants.NS_TIME_BASE;
            if (maxDuaration > m_timelineDuration) {
                maxDuaration = m_timelineDuration;
            }
            int minTimeSpanPixel = (int) Math.floor(minDuaration * m_pixelPerMicrosecond + 0.5D);
            int maxTimeSpanPixel = (int) Math.floor(maxDuaration * m_pixelPerMicrosecond + 0.5D);
            timelineTimeSpan.setMinTimeSpanPixel(minTimeSpanPixel);
            timelineTimeSpan.setMaxTimeSpanPixel(maxTimeSpanPixel);

            //
            final int tmpTotalWidth = getSequenceWidth();
            double xLeft = inPoint * m_pixelPerMicrosecond;
            double width = (outPoint - inPoint) * m_pixelPerMicrosecond;
            int spanWidth = (int) Math.floor(width + 0.5D);
            int shadowMarginWidth = (int) Math.floor(xLeft + 0.5D);
            final View viewLeftMargin = new View(m_context);
            int backgrdColor = Color.parseColor("#bf000000");
            viewLeftMargin.setBackgroundColor(backgrdColor);
            LayoutParams viewLeftMarginParams = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
            viewLeftMarginParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
            viewLeftMarginParams.width = shadowMarginWidth;
            viewLeftMarginParams.setMargins(0, 0, tmpTotalWidth - shadowMarginWidth, 0);
            m_timeSpanRelativeLayout.addView(viewLeftMargin, viewLeftMarginParams);

            final View viewRightMargin = new View(m_context);
            viewRightMargin.setBackgroundColor(backgrdColor);
            LayoutParams viewRightMarginParams = new LayoutParams(tmpTotalWidth - (shadowMarginWidth + spanWidth), ViewGroup.LayoutParams.MATCH_PARENT);
            viewRightMarginParams.width = tmpTotalWidth - (shadowMarginWidth + spanWidth);
            viewRightMarginParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            viewRightMarginParams.setMargins(shadowMarginWidth + spanWidth, 0, 0, 0);
            m_timeSpanRelativeLayout.addView(viewRightMargin, viewRightMarginParams);

            timelineTimeSpan.setMarginChangeListener(new NvsTimelineTimeSpan.OnMarginChangeListener() {
                @Override
                public void onChange(int leftMargin, int timeSpanWidth) {
                    LayoutParams viewLeftMarginParams = (LayoutParams) viewLeftMargin.getLayoutParams();
                    viewLeftMarginParams.width = leftMargin;
                    viewLeftMarginParams.setMargins(0, 0, tmpTotalWidth - leftMargin, 0);
                    viewLeftMargin.setLayoutParams(viewLeftMarginParams);

                    LayoutParams viewRightMarginParams = (LayoutParams) viewRightMargin.getLayoutParams();
                    viewRightMarginParams.width = tmpTotalWidth - (timeSpanWidth + leftMargin);
                    viewRightMarginParams.setMargins(leftMargin + timeSpanWidth, 0, 0, 0);
                    viewRightMargin.setLayoutParams(viewRightMarginParams);
                }
            });
        }

        return timelineTimeSpan;
    }

    /*
     * 添加扩展的timeSpan，可以微调时间值
     * Added extended timeSpan to fine-tune time values
     * */
    public NvsTimelineTimeSpanExt addTimeSpanExt(long inPoint, long outPoint, ChangeSpeedCurveInfo curveSpeed, int index) {
        if (inPoint < 0 || outPoint < 0 || inPoint >= outPoint)
            return null;
        if (m_timeSpanType.compareTo("NvsTimelineTimeSpanExt") != 0)
            return null;
        if (outPoint > m_timelineDuration)
            outPoint = m_timelineDuration;
        NvsTimelineTimeSpanExt timeSpanExt = new NvsTimelineTimeSpanExt(m_context);
        timeSpanExt.setMultiThumbnailSequenceView(m_multiThumbnailSequenceView);
        timeSpanExt.setInPoint(inPoint);
        timeSpanExt.setOutPoint(outPoint);
        timeSpanExt.setDuration(timeSpanExt.formatTimeStrWithUs(outPoint - inPoint));
        if (curveSpeed != null) {
            timeSpanExt.setCurveName(curveSpeed.mName);
        }
        timeSpanExt.setIndex(index);
        timeSpanExt.setPixelPerMicrosecond(m_pixelPerMicrosecond);
        int lLeftHandleWidth = timeSpanExt.getLLeftHandleWidth();
        int totalWidth = getSequenceWidth() + 2 * lLeftHandleWidth;
        timeSpanExt.setTotalWidth(totalWidth);

        //
        addTimeSpanLayout(lLeftHandleWidth);
        //
        double xLeft = inPoint * m_pixelPerMicrosecond;
        double width = (outPoint - inPoint) * m_pixelPerMicrosecond;
        width += 2 * lLeftHandleWidth;
        int spanWidth = (int) Math.floor(width + 0.5D);
        int leftMargin = (int) Math.floor(xLeft + 0.5D);
        LayoutParams spanItemParams = new LayoutParams(spanWidth, ScreenUtils.dip2px(m_context, 40));
        spanItemParams.setMargins(leftMargin, 0, totalWidth - (leftMargin + spanWidth), 0);
//        spanItemParams.setMargins(leftMargin, LayoutParams.MATCH_PARENT, totalWidth - (leftMargin + spanWidth), 0);
        timeSpanExt.setLayoutParams(spanItemParams);

        TimeSpanSplitView timeSpanSplitView = new TimeSpanSplitView(m_context);
        LayoutParams timeSpanSplitViewParams = new LayoutParams(ScreenUtils.dip2px(m_context, 12), ScreenUtils.dip2px(m_context, 40));
        timeSpanSplitViewParams.setMargins(leftMargin + spanWidth - lLeftHandleWidth - ScreenUtils.dip2px(m_context, 6), 0, 0, 0);
        timeSpanSplitView.setLayoutParams(timeSpanSplitViewParams);

        m_timeSpanSplitArray.add(timeSpanSplitView);

//        final int tmpTotalWidth = totalWidth;
//        final int tmpLLeftHandleWidth = lLeftHandleWidth;
//        final View viewLeftMargin = new View(m_context);
//        int backgrdColor = Color.parseColor("#bf000000");
//        viewLeftMargin.setBackgroundColor(backgrdColor);
//        int tmpMarginHeight = timeSpanExt.getLTopHandleHeight();
//        LayoutParams viewLeftMarginParams = new LayoutParams(0, tmpMarginHeight);
//        viewLeftMarginParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
//        viewLeftMarginParams.width = leftMargin;
//        viewLeftMarginParams.setMargins(tmpLLeftHandleWidth, 0, tmpTotalWidth - tmpLLeftHandleWidth - leftMargin, 0);
//        m_timeSpanRelativeLayout.addView(viewLeftMargin, viewLeftMarginParams);
//
//        final View viewRightMargin = new View(m_context);
//        viewRightMargin.setBackgroundColor(backgrdColor);
//        LayoutParams viewRightMarginParams = new LayoutParams(tmpTotalWidth - (leftMargin + spanWidth), tmpMarginHeight);
//        viewRightMarginParams.width = tmpTotalWidth - (leftMargin + spanWidth);
//        viewRightMarginParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
//        viewRightMarginParams.setMargins(leftMargin + spanWidth - lLeftHandleWidth, 0, lLeftHandleWidth, 0);
//        m_timeSpanRelativeLayout.addView(viewRightMargin, viewRightMarginParams);
//
//        timeSpanExt.setMarginChangeListener((leftMargin1, timeSpanWidth) -> {
//            LayoutParams viewLeftMarginParams1 = (LayoutParams) viewLeftMargin.getLayoutParams();
//            viewLeftMarginParams1.width = leftMargin1 - tmpLLeftHandleWidth * 2;
//            viewLeftMarginParams1.setMargins(tmpLLeftHandleWidth, 0, tmpTotalWidth - leftMargin1, 0);
//            viewLeftMargin.setLayoutParams(viewLeftMarginParams1);
//
//            LayoutParams viewRightMarginParams1 = (LayoutParams) viewRightMargin.getLayoutParams();
//            viewRightMarginParams1.width = tmpTotalWidth - (timeSpanWidth + leftMargin1) - tmpLLeftHandleWidth * 2;
//            viewRightMarginParams1.setMargins(leftMargin1 + timeSpanWidth, 0, tmpLLeftHandleWidth, 0);
//            viewRightMargin.setLayoutParams(viewRightMarginParams1);
//        });
        timeSpanExt.setVisibility(INVISIBLE);

        timeSpanExt.setOnChangeListener((NvsTimelineTimeSpanExt.OnTrimOutChangeListener) (timeStamp, isDragEnd) -> {
//            ArrayList<MultiThumbnailSequenceView.ThumbnailSequenceDesc> thumbnailSequenceDescArray = new ArrayList<>();
//            thumbnailSequenceDescArray.addAll(m_multiThumbnailSequenceView.getThumbnailSequenceDescArray());
//            LogUtils.e(TAG, thumbnailSequenceDescArray.get(timeSpanExt.getIndex()).outPoint);
//            thumbnailSequenceDescArray.get(timeSpanExt.getIndex()).outPoint = timeSpanExt.getOutPoint();
//            LogUtils.e(TAG, timeStamp);
//            m_multiThumbnailSequenceView.setThumbnailSequenceDescArray(thumbnailSequenceDescArray);
            if (m_spanExtSelectListener != null) {
                m_spanExtSelectListener.onSpanMove(timeStamp);
            }
        });

        timeSpanExt.setOnChangeListener((NvsTimelineTimeSpanExt.OnTrimInChangeListener) (timeStamp, isDragEnd) -> {
            if (m_spanExtSelectListener != null) {
                m_spanExtSelectListener.onSpanMove(timeStamp);
            }
        });

        m_timeSpanRelativeLayout.addView(timeSpanExt);
        m_timeSpanRelativeLayout.addView(timeSpanSplitView);
        return timeSpanExt;
    }

    /*
     * 放大MultiThumbnailSequence序列
     * Enlarge MultiThumbnailSequence sequence
     * */
    public void ZoomInSequence() {
        if (m_pixelPerMicrosecond > m_maxPixelPerMicrosecond) {
            return;
        }
        double scalFactor = 1.25;
        updateSequence(scalFactor);
    }

    //放大MultiThumbnailSequence序列
    public void ZoomInSequence(double scalFactor) {
        if (m_pixelPerMicrosecond > m_maxPixelPerMicrosecond)
            return;
        updateSequence(scalFactor);
    }

    /*
     * 缩小MultiThumbnailSequence序列
     * Reduce MultiThumbnailSequence sequence
     * */
    public void ZoomOutSequence() {
        if (m_pixelPerMicrosecond < m_minPixelPerMicrosecond)
            return;
        double scalFactor = 0.8;
        updateSequence(scalFactor);
    }

    private void updateSequence(double scaleFactor) {
        int m_curAnchor = m_sequencLeftPadding;
        m_multiThumbnailSequenceView.scaleWithAnchor(scaleFactor, m_curAnchor);
        m_pixelPerMicrosecond = m_multiThumbnailSequenceView.getPixelPerMicrosecond();

        // layoutTimeSpan ZoomIn and ZoomOut
        int totalWidth = getSequenceWidth();
        LinearLayout.LayoutParams timeSpanRelativeParams = (LinearLayout.LayoutParams) m_timeSpanRelativeLayout.getLayoutParams();
        if (timeSpanRelativeParams == null) {
            return;
        }

        timeSpanRelativeParams.width = totalWidth;
        m_timeSpanRelativeLayout.setLayoutParams(timeSpanRelativeParams);
        int count = m_timelineTimeSpanArray.size();
        for (int index = 0; index < count; ++index) {
            NvsTimelineTimeSpan timelineTimeSpan = m_timelineTimeSpanArray.get(index);
            double xLeft = timelineTimeSpan.getInPoint() * m_pixelPerMicrosecond;
            double width = (timelineTimeSpan.getOutPoint() - timelineTimeSpan.getInPoint()) * m_pixelPerMicrosecond;
            timelineTimeSpan.setTotalWidth(totalWidth);
            timelineTimeSpan.setPixelPerMicrosecond(m_pixelPerMicrosecond);
            int spanWidth = (int) Math.floor(width + 0.5D);
            int leftValue = (int) Math.floor(xLeft + 0.5D);

            LayoutParams relativeParams = (LayoutParams) timelineTimeSpan.getLayoutParams();
            relativeParams.width = spanWidth;
            relativeParams.setMargins(leftValue, 0, totalWidth - (leftValue + spanWidth), 0);
            timelineTimeSpan.setLayoutParams(relativeParams);
        }
    }


    private NvsTimelineTimeSpan createTimeSpan(long inPoint, long outPoint) {
        if (inPoint < 0 || outPoint < 0 || inPoint >= outPoint)
            return null;
        if (outPoint > m_timelineDuration)
            outPoint = m_timelineDuration;
        NvsTimelineTimeSpan timelineTimeSpan = new NvsTimelineTimeSpan(m_context);
        timelineTimeSpan.setInPoint(inPoint);
        timelineTimeSpan.setOutPoint(outPoint);
        timelineTimeSpan.setPixelPerMicrosecond(m_pixelPerMicrosecond);
        int totalWidth = getSequenceWidth();
        timelineTimeSpan.setTotalWidth(totalWidth);

        //
        addTimeSpanLayout(0);
        //
        double xLeft = inPoint * m_pixelPerMicrosecond;
        double width = (outPoint - inPoint) * m_pixelPerMicrosecond;
        int spanWidth = (int) Math.floor(width + 0.5D);
        int leftMargin = (int) Math.floor(xLeft + 0.5D);
        LayoutParams spanItemParams = new LayoutParams(spanWidth, LayoutParams.MATCH_PARENT);
        spanItemParams.setMargins(leftMargin, LayoutParams.MATCH_PARENT, totalWidth - (leftMargin + spanWidth), 0);
        timelineTimeSpan.setLayoutParams(spanItemParams);

        boolean add = true;
        if (outPoint <= m_multiThumbnailSequenceView.mapTimelinePosFromX(0)) {
            add = false;
        }
        if (inPoint >= m_multiThumbnailSequenceView.mapTimelinePosFromX(2 * m_screenCentral)) {
            add = false;
        }

        if (add) {
            m_timeSpanRelativeLayout.addView(timelineTimeSpan);
            //updateTimeSpanShadow(mTimelineTimeSpan);
        }
        m_timelineTimeSpanArray.add(timelineTimeSpan);
        return timelineTimeSpan;
    }

    /*
     * Selected by user selection timeSpan
     * Selected by user selection timeSpan
     * */
    public void selectTimeSpan(NvsTimelineTimeSpan timeSpan) {
        unSelectAllTimeSpan();
        timeSpan.setHasSelected(true);
        timeSpan.requestLayout();
        timeSpan.bringToFront();
    }

    public int getSequenceWidth() {
        return (int) Math.floor(m_timelineDuration * m_pixelPerMicrosecond + 0.5D);
    }

    public MultiThumbnailSequenceView getMultiThumbnailSequenceView() {
        return m_multiThumbnailSequenceView;
    }

    public int timeSpanCount() {
        return m_timeSpanRelativeLayout.getChildCount();
    }

    public void deleteSelectedTimeSpan(NvsTimelineTimeSpan timeSpan) {
        int count = m_timeSpanRelativeLayout.getChildCount();
        if (count > 0) {
            m_timeSpanRelativeLayout.removeView(timeSpan);
            m_timelineTimeSpanArray.remove(timeSpan);
        }
    }

    public void deleteAllTimeSpan() {
        int countTimeSpan = m_timeSpanRelativeLayout.getChildCount();
        if (countTimeSpan > 0) {
            m_timeSpanRelativeLayout.removeAllViews();
        }
        int arraySize = m_timelineTimeSpanArray.size();
        if (arraySize > 0) {
            m_timelineTimeSpanArray.clear();
        }
        m_timelineTimeSpanExtArray.clear();
    }

    private void updateTimeSpanShadow(NvsTimelineTimeSpan timeSpan) {
        long inPoint = timeSpan.getInPoint();
        long outPoint = timeSpan.getOutPoint();
        long newIn = inPoint;
        long newOut = outPoint;
        long left = m_multiThumbnailSequenceView.mapTimelinePosFromX(0);
        if (inPoint < left) {
            newIn = left;
        }

        long right = m_multiThumbnailSequenceView.mapTimelinePosFromX(2 * m_screenCentral);
        if (outPoint > right) {
            newOut = right;
        }
        double xLeft = newIn * m_pixelPerMicrosecond;
        double width = (newOut - newIn) * m_pixelPerMicrosecond;
        int spanWidth = (int) Math.floor(width + 0.5D);
        int leftValue = (int) Math.floor(xLeft + 0.5D);
        int timeSpanShadowWidth = timeSpan.getLayoutParams().width;
        int subViewScrollValue = (int) Math.floor(inPoint * m_pixelPerMicrosecond + 0.5D);
        leftValue = leftValue - subViewScrollValue;
        LayoutParams relativeParams = (LayoutParams) timeSpan.getTimeSpanshadowView().getLayoutParams();
        relativeParams.width = spanWidth;
        relativeParams.setMargins(leftValue, LayoutParams.MATCH_PARENT, timeSpanShadowWidth - (leftValue + spanWidth), 0);
        timeSpan.getTimeSpanshadowView().setLayoutParams(relativeParams);
    }

    private void addTimeSpanLayout(int beyondHandleVal) {
        if (m_sequenceLinearLayout.getParent() != null) {
            return;
        }
        // start padding
        addPadding(m_timeSpanLeftPadding - beyondHandleVal);
        int totalWidth = getSequenceWidth() + 2 * beyondHandleVal;
        LinearLayout.LayoutParams timeSpanRelativeParams = new LinearLayout.LayoutParams(totalWidth, LinearLayout.LayoutParams.MATCH_PARENT);
        timeSpanRelativeParams.setMargins(m_timeTextWidth, sequenceTopPadding, 0, 0);
        m_sequenceLinearLayout.addView(m_timeSpanRelativeLayout, timeSpanRelativeParams);
        LayoutParams itemParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        this.addView(m_sequenceLinearLayout, itemParams);
    }

    public void unSelectAllTimeSpan() {
        BackupData.instance().setClipIndex(-1);
        for (int index = 0; index < m_timelineTimeSpanArray.size(); ++index) {
            NvsTimelineTimeSpan timeSpan = m_timelineTimeSpanArray.get(index);
            if (timeSpan.isHasSelected()) {
                timeSpan.setHasSelected(false);
                timeSpan.requestLayout();
            }
        }
        for (int i = 0; i < m_timelineTimeSpanExtArray.size(); i++) {
            m_timelineTimeSpanExtArray.get(i).setVisibility(INVISIBLE);
        }
        unSelectTimeSpanSplit(true);
    }

    private void removeAllLayout() {
        deleteAllTimeSpan();
        int countLinearChild = m_sequenceLinearLayout.getChildCount();
        if (countLinearChild > 0) {
            m_sequenceLinearLayout.removeAllViews();
        }
        int rootLinearChild = m_rootLinearLayout.getChildCount();
        if (rootLinearChild > 0) {
            m_rootLinearLayout.removeAllViews();
        }

        int countEditorChild = this.getChildCount();
        if (countEditorChild > 0) {
            this.removeAllViews();
        }
    }

    private void init() {
        DisplayMetrics dm = this.getResources().getDisplayMetrics();
        int screenWidth = dm.widthPixels;
        sequenceTopPadding = ScreenUtils.dip2px(m_context, 50);
        m_pixelPerMicrosecond = screenWidth / 20 / TIMEBASE;
        m_maxPixelPerMicrosecond = m_pixelPerMicrosecond * Math.pow(1.25, 5);//NvsMultiThumbnailSequenceView放大的m_pixelPerMicrosecond最大值
        m_minPixelPerMicrosecond = m_pixelPerMicrosecond * Math.pow(0.8, 5);//NvsMultiThumbnailSequenceView缩小的m_pixelPerMicrosecond最小值
        m_screenCentral = (int) Math.floor(screenWidth / 2 + 0.5D);
        m_timelineTimeSpanArray = new ArrayList<>();
        m_timelineTimeSpanExtArray = new ArrayList<>();
        m_timeSpanSplitArray = new ArrayList<>();
    }

    private void addPadding(int padding) {
        LinearLayout.LayoutParams paddinParams = new LinearLayout.LayoutParams(padding, LinearLayout.LayoutParams.MATCH_PARENT);
        View view = new View(m_context);
        m_sequenceLinearLayout.addView(view, paddinParams);
    }
}
